/* Release 3.10 */
/*-------------------------------------------------------------------------*
*                                                                          *
*  STRSTREAM.CPP - 2.1 file stream class implementations.      		   *
*                                                                          *
*  COPYRIGHT (C) 1989..1992 Clarion Software Corporation.                  *
*  All Rights Reserved                                                     *
*                                                                          *
*--------------------------------------------------------------------------*/

#include <clib.h>
#include <strstrea.hpp>

#pragma module(init_prio=>22)

//**************************************************************************
//  strstreambuf implementation
//**************************************************************************


strstreambuf::strstreambuf() : streambuf(NULL, 0) {

  flags=dynamic;
  allocf=NULL;
  freef=NULL;
  next_alloc=512;
  init(NULL, 0, NULL);
}

strstreambuf::strstreambuf(int n) : streambuf(NULL, 0) {

  flags=dynamic;
  allocf=NULL;
  freef=NULL;
  next_alloc=n;
  init(NULL, 0, NULL);
}
strstreambuf::strstreambuf(void * (*a)(long), void (*f)(void*)) : streambuf(NULL, 0) {

  flags=dynamic;
  allocf=a;
  freef=f;
  next_alloc=512;
  init(NULL, 0, NULL);
}

strstreambuf::strstreambuf(char *ptr, int n, char *pstart) : streambuf(NULL, 0) {

  int len;

  if(n < 0) {
    flags=unlimited;
    len= INT_MAX;
  }
  else
    flags=0;
  if(n == 0)
    len=strlen((char *)ptr);
  else if(n > 0)
    len=n;
  next_alloc=0;
  allocf=NULL;
  freef=NULL;
  init(ptr, len, pstart);
}

strstreambuf::~strstreambuf() {

  if((flags&dynamic) && (!(flags&frozen))) {
    if(freef)
      freef(base());
    else
      delete base();
  }
}

void strstreambuf::freeze(int f) {

  flags |= frozen*(f == 1);
}


char *strstreambuf::str() {

  flags |= frozen;
  return base();
}


int strstreambuf::doallocate() {

  char *b;

  b=(char *) allocf(512);
  if(b == NULL)
    return EOF;
  setb(b, b+512, 1);
  setg(b, b, b+512);
  setp(b, b+512);
  return 1;
}

int strstreambuf::overflow(int c) {

  char *nb, *ob;
  int old_size, new_size, in_pbuf, in_gbuf;

  if(flags&frozen)
    return EOF;

  old_size=ebuf()-base();
  new_size=old_size+next_alloc;
  in_pbuf=pptr()-pbase();
  in_gbuf=gptr()-eback();
  ob=base();

  if(allocf)
    nb = (char *) allocf(new_size);
  else
    nb = new char[new_size];
  if(nb == NULL)
    return EOF;
  setb(nb, nb+new_size);
  setg(nb, nb, nb+new_size);
  setp(nb, nb+new_size);
  if(ob) {
    memcpy(nb, ob, old_size);
    pbump(in_pbuf);
    gbump(in_gbuf);
    if(freef)
      freef(ob);
    else
      delete ob;
  }
  if(c != EOF)
    sputc(c);
  return c;
}

int strstreambuf::underflow() {

  return EOF;
}


streambuf *strstreambuf::setbuf(char *b, int n) {

  if(b == NULL)
    next_alloc=n;
  else {
    setb(b, b+512, 0);
    setg(b, b, b+512);
    setp(b, b+512);
  }
  return this;
}

streampos strstreambuf::seekoff(streamoff pos, ios::seek_dir d, int mode) {

  streampos ret;

  if(mode & ios::in) {
    switch(d) {
      case ios::beg :
        setg(eback(), eback()+pos, egptr());
        break;
      case ios::cur :
        gbump((int)pos);
        break;
      case ios::end :
        setg(eback(), egptr()+pos, egptr());
        break;
    }
    if((gptr() > egptr()) || (gptr() < eback()))
      return -1L;
    ret = gptr()-eback();
  }

  if(mode & ios::out) {
    switch(d) {
      case ios::beg :
        setp(pbase(), epptr());
        pbump((int)pos);
        break;
      case ios::cur :
        pbump((int)pos);
        break;
      case ios::end :
        setp(pbase(), epptr());
        pbump((int)(epptr()-pbase()+pos));
        break;
    }
    if((pptr() > epptr()) || (pptr() < base()))
      return -1L;
    ret = pptr()-pbase();
  }
  return ret;
}


void   strstreambuf::init(char *ptr, int sz, char *pstart) {

  char *eg, *pp;

  setb(ptr, ptr+sz, 0);

  if(pstart == NULL) {
    eg=ebuf();
    pp=ebuf();
  }
  else {
    eg=pstart;
    pp=pstart;
  }
  setg(ptr, ptr, eg);
  setp(pp, ebuf());
}

//**************************************************************************
//  strstreambase implementation
//**************************************************************************


strstreambase::strstreambase(char *g, int n, char *p) : buf(g, n, p) {

  ios::init(&buf);

}

strstreambase::strstreambase() {

  ios::init(&buf);
}

strstreambase::~strstreambase() {

}

//**************************************************************************
//  istrstream implementation
//**************************************************************************

istrstream::istrstream(char *s) : strstreambase(s, 0, NULL),
                                  istream(rdbuf()) {

}

istrstream::istrstream(char *s, int n) : strstreambase(s, n, NULL),
                                         istream(rdbuf()) {

}

istrstream::~istrstream() {

}

ostrstream::ostrstream() : ostream(rdbuf()) {

}

ostrstream::ostrstream(char *cp, int n, int mode) : strstreambase(cp, n, cp),
                                                    ostream(rdbuf()) {
  if(mode&(ios::ate|ios::app))
    seekp(strlen(cp));
}

ostrstream::~ostrstream() {

}

//**************************************************************************
//  istrstream implementation
//**************************************************************************

strstream::strstream() : strstreambase(),
                         iostream(rdbuf()) {

}

strstream::strstream(char *cp, int n, int mode) : strstreambase(cp, n, cp),
                                                  iostream(rdbuf()) {

  if(mode&(ios::ate|ios::app))
    seekp(strlen(cp));
}

strstream::~strstream() {

}

